﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;

namespace HtmlReport
{
    public class HtmlReportExporter
    {
        private int _PageCount = 0;
        List<ReportElement> _Elements = new List<ReportElement>();
        string TemplateCode = "";
        private DataSet _DataSource = null;
        private string _TempateFile = "";
        public string TempateFile
        {
            set
            {
                _TempateFile = value;
                ParseTemplate();
            }
            get
            {
                return _TempateFile;
            }
        }
        private static string _TmpDir = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetCallingAssembly().Location) + "\\TmpFiles";

        public static string TmpDir
        {
            set
            {
                _TmpDir = value;
            }
            get
            {
                return _TmpDir;
            }
        }
        public int PageCount
        {
            set
            {
                _PageCount = value;
            }
            get
            {
                return _PageCount;
            }
        }
        public DataSet DataSource
        {
            set
            {
                _DataSource = value;
            }
            get
            {
                return _DataSource;
            }
        }
        private bool CompareString(ref string str1, string str2, int start)
        {
            if (str2 == null) return false;
            if (str1 == null) return false;
            int end = str2.Length;
            if (end + start > str1.Length) return false;
            for (int i = 0; i < end; i++)
                if (str1[i + start] != str2[i]) return false;
            return true;

        }
        private ElementAtributes GetAtributes(string content)
        {
            ElementAtributes list = new ElementAtributes();
            content = content.Trim();
            content = content.Replace("\r\n", " ");
            content = content.Replace("\t", " ");
            while (content.IndexOf("  ") >= 0)
                content = content.Replace("  ", " ");
            int oldIndex = 0;
            int index = 0;
            do
            {
                oldIndex = index;
                index = content.IndexOf("=", index);
                if (index > 0)
                {
                    string key = content.Substring(oldIndex, index - oldIndex).Trim();
                    string value = "";
                    index++;
                    string openchar = "";
                    do
                    {
                        char chr = content[index];
                        if ((chr != ' ') && (chr != '\'') && (chr != '\"'))
                        {
                            break;
                        }
                        index++;
                        openchar = chr.ToString().Trim();
                    }
                    while (true);
                    if (openchar == "")
                    {
                        openchar = " ";
                    }
                    int endIndex = content.IndexOf(openchar, index);
                    if (endIndex < 0)
                    {
                        value = content.Substring(index);
                    }
                    else
                    {
                        value = content.Substring(index, endIndex - index);
                        index = endIndex + 1;
                    }
                    list.Add(key, value);
                }
                else
                {
                    break;
                }
            } while (true);

            return list;
        }
        private void AddPosTag(List<PosTag> list, string tagName, ref int StartPos, int EndPos, string content)
        {
            int startAtribute = StartPos + Tags.BEGINSCRIPT.Length + tagName.Length;
            string AtributeContent = content.Substring(startAtribute, EndPos - startAtribute);
            PosTag tag = new PosTag();
            tag.TagName = tagName;
            tag.StartPos = StartPos;
            tag.EndPos = EndPos;
            tag.Atributes = GetAtributes(AtributeContent);
            list.Add(tag);
            StartPos = EndPos;
        }
        private List<PosTag> GetTags(ref string content, int start, int end)
        {
            List<PosTag> list = new List<PosTag>();
            for (int i = start; i <= end; i++)
            {
                if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.BEGINREPORT, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.BEGINREPORT, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.ENDREPORT, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.ENDREPORT, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.BEGINPAGEHEADER, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.BEGINPAGEHEADER, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.ENDPAGEHEADER, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.ENDPAGEHEADER, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.BEGINPAGEFOOTER, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.BEGINPAGEFOOTER, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.ENDPAGEFOOTER, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.ENDPAGEFOOTER, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.BEGINPAGEDETAIL, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.BEGINPAGEDETAIL, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.ENDPAGEDETAIL, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.ENDPAGEDETAIL, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.BEGINREPORTFOOTER, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.BEGINREPORTFOOTER, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.ENDREPORTFOOTER, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.ENDREPORTFOOTER, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.BEGINREPORTHEADER, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.BEGINREPORTHEADER, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.ENDREPORTHEADER, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.ENDREPORTHEADER, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.BEGINGROUPDATA, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.BEGINGROUPDATA, ref i, indexEnd, content);
                }
                else if (CompareString(ref content, Tags.BEGINSCRIPT + Tags.ENDGROUPDATA, i))
                {
                    int indexEnd = content.IndexOf(Tags.ENDSCRIPT, i);
                    if (indexEnd < 0) break;
                    AddPosTag(list, Tags.ENDGROUPDATA, ref i, indexEnd, content);
                }
            }
            return list;
        }
        private int FindEndTag(List<PosTag> list, int index, string OpenTag, string EndTag)
        {
            int count = 0;
            for (int i = index; i < list.Count; i++)
            {

                if (list[i].TagName == EndTag)
                {
                    if (count == 0)
                    {
                        return i;
                    }
                    count--;
                }
                if (list[i].TagName == OpenTag)
                {
                    count++;
                }
            }
            return -1;
        }
        private string ReadTemplate()
        {
            System.IO.StreamReader strm = null;
            if (System.IO.File.Exists(_TempateFile))
            {
                strm = System.IO.File.OpenText(_TempateFile);
            }
            if (strm != null)
            {
                string content = strm.ReadToEnd();
                strm.Close();
                return content;
            }
            return "";
        }
        private void ParseTemplate()
        {
            _Elements.Clear();
            string sContent = ReadTemplate();
            TemplateCode = sContent;
            if (sContent == "") return;
            List<PosTag> list = GetTags(ref sContent, 0, sContent.Length);
            ParseRecusive(_Elements, list, 0, list.Count - 1, ref sContent);
            foreach (ReportElement e in _Elements)
            {
                e.Exporter = this;
                e.AllowPageBreak = true;
            }
        }
        private void AddElementAtributes(ReportElement element, List<PosTag> list, ref string content, int index, int stopindex)
        {
            element.ElementName = list[index].TagName;
            element.BeginTags = list[index];
            element.EndTags = list[stopindex];
        }
        private void ParseRecusive(List<ReportElement> lsElement, List<PosTag> list, int indexstart, int indexend, ref string content)
        {
            for (int index = indexstart; index <= indexend; index++)
            {
                if (list[index].TagName == Tags.BEGINREPORT)
                {
                    int stopindex = FindEndTag(list, index + 1, Tags.BEGINREPORT, Tags.ENDREPORT);
                    if (stopindex >= 0)
                    {
                        Report element = new Report();
                        AddElementAtributes(element, list, ref content, index, stopindex);
                        lsElement.Add(element);
                        ParseRecusive(element.Elements, list, index + 1, stopindex - 1, ref content);
                        index = stopindex - 1;
                    }
                }
                else if (list[index].TagName == Tags.BEGINREPORTHEADER)
                {
                    int stopindex = FindEndTag(list, index + 1, Tags.BEGINREPORTHEADER, Tags.ENDREPORTHEADER);
                    if (stopindex >= 0)
                    {
                        ReportHeader element = new ReportHeader();
                        AddElementAtributes(element, list, ref content, index, stopindex);
                        lsElement.Add(element);
                        ParseRecusive(element.Elements, list, index + 1, stopindex - 1, ref content);
                        index = stopindex - 1;
                    }
                }
                else if (list[index].TagName == Tags.BEGINREPORTFOOTER)
                {
                    int stopindex = FindEndTag(list, index + 1, Tags.BEGINREPORTFOOTER, Tags.ENDREPORTFOOTER);
                    if (stopindex >= 0)
                    {
                        ReportFooter element = new ReportFooter();
                        AddElementAtributes(element, list, ref content, index, stopindex);
                        lsElement.Add(element);
                        ParseRecusive(element.Elements, list, index + 1, stopindex - 1, ref content);
                        index = stopindex - 1;
                    }
                }
                else if (list[index].TagName == Tags.BEGINGROUPDATA)
                {
                    int stopindex = FindEndTag(list, index + 1, Tags.BEGINGROUPDATA, Tags.ENDGROUPDATA);
                    if (stopindex >= 0)
                    {
                        GroupData element = new GroupData();
                        AddElementAtributes(element, list, ref content, index, stopindex);
                        lsElement.Add(element);
                        ParseRecusive(element.Elements, list, index + 1, stopindex - 1, ref content);
                        index = stopindex - 1;
                    }
                }
                else if (list[index].TagName == Tags.BEGINPAGEHEADER)
                {
                    int stopindex = FindEndTag(list, index + 1, Tags.BEGINPAGEHEADER, Tags.ENDPAGEHEADER);
                    if (stopindex >= 0)
                    {
                        PageHeader element = new PageHeader();
                        AddElementAtributes(element, list, ref content, index, stopindex);
                        lsElement.Add(element);
                        ParseRecusive(element.Elements, list, index + 1, stopindex - 1, ref content);
                        index = stopindex - 1;
                    }
                }
                else if (list[index].TagName == Tags.BEGINPAGEFOOTER)
                {
                    int stopindex = FindEndTag(list, index + 1, Tags.BEGINPAGEFOOTER, Tags.ENDPAGEFOOTER);
                    if (stopindex >= 0)
                    {
                        PageFooter element = new PageFooter();
                        AddElementAtributes(element, list, ref content, index, stopindex);
                        lsElement.Add(element);
                        ParseRecusive(element.Elements, list, index + 1, stopindex - 1, ref content);
                        index = stopindex - 1;
                    }
                }
                else if (list[index].TagName == Tags.BEGINPAGEDETAIL)
                {
                    int stopindex = FindEndTag(list, index + 1, Tags.BEGINPAGEDETAIL, Tags.ENDPAGEDETAIL);
                    if (stopindex >= 0)
                    {
                        PageDetail element = new PageDetail();
                        AddElementAtributes(element, list, ref content, index, stopindex);
                        lsElement.Add(element);
                        ParseRecusive(element.Elements, list, index + 1, stopindex - 1, ref content);
                        index = stopindex - 1;
                    }
                }
                if (list[index].TagName == Tags.BEGINCOLS)
                {
                    int stopindex = FindEndTag(list, index + 1, Tags.BEGINCOLS, Tags.ENDCOLS);
                    if (stopindex >= 0)
                    {
                        ReportCols element = new ReportCols();
                        AddElementAtributes(element, list, ref content, index, stopindex);
                        lsElement.Add(element);
                        ParseRecusive(element.Elements, list, index + 1, stopindex - 1, ref content);
                        index = stopindex - 1;
                    }
                }
            }
        }
        public string ExportReport()
        {
            _PageCount = 1;
            string st = this.TemplateCode;
            string stOut = "";
            int index = 0;
            if (_Elements.Count > 0)
            {
                for (int i = 0; i < _Elements.Count; i++)
                {
                    if (index >= st.Length) break;
                    stOut += st.Substring(index, _Elements[i].BeginTags.StartPos - index) + _Elements[i].DataBind(_DataSource, null, null, -1, TemplateCode);
                    index = _Elements[i].EndTags.EndPos + Tags.ENDSCRIPT.Length;
                }
            }
            else
            {
                stOut = st;
            }
            return stOut;
        }
        private Dictionary<string, object> _Parameters = new Dictionary<string, object>();
        public Dictionary<string, object> Parameters
        {
            set
            {
                _Parameters = value;
            }
            get
            {
                return _Parameters;
            }
        }
    }
    internal abstract class ReportElement
    {
        private string _ElementName = "";
        private PosTag _BeginTags = new PosTag();
        private PosTag _EndTags = new PosTag();
        List<ReportElement> _Elements = new List<ReportElement>();
        private HtmlReportExporter exporter = null;
        private bool _AllowPageBreak = false;
        public DataRow[] RowsAffected = null;
        public bool AllowPageBreak
        {
            set
            {
                _AllowPageBreak = value;
            }
            get
            {
                return _AllowPageBreak;
            }
        }
        public HtmlReportExporter Exporter
        {
            set
            {
                exporter = value;
                foreach (ReportElement o in _Elements)
                {
                    o.Exporter = exporter;
                }
            }
            get
            {
                return exporter;
            }
        }
        public PosTag BeginTags
        {
            set
            {
                _BeginTags = value;
            }
            get
            {
                return _BeginTags;
            }
        }
        public PosTag EndTags
        {
            set
            {
                _EndTags = value;
            }
            get
            {
                return _EndTags;
            }
        }
        public List<ReportElement> Elements
        {
            set
            {
                _Elements = value;
            }
            get
            {
                return _Elements;
            }
        }
        public string ElementName
        {
            set
            {
                _ElementName = value;
            }
            get
            {
                return _ElementName;
            }
        }
        public List<ReportHeader> GetHeaders()
        {
            List<ReportHeader> ls = new List<ReportHeader>();
            foreach (ReportElement e in Elements)
            {
                if (e is ReportHeader)
                    ls.Add((ReportHeader)e);
            }
            return ls;
        }
        public List<GroupData> GetGroups()
        {
            List<GroupData> ls = new List<GroupData>();
            foreach (ReportElement e in Elements)
            {
                if (e is GroupData)
                    ls.Add((GroupData)e);
            }
            return ls;
        }
        public List<PageHeader> GetPageHeaders()
        {
            List<PageHeader> ls = new List<PageHeader>();
            foreach (ReportElement e in Elements)
            {
                if (e is PageHeader)
                    ls.Add((PageHeader)e);
            }
            return ls;
        }
        public List<PageDetail> GetPageDetails()
        {
            List<PageDetail> ls = new List<PageDetail>();
            foreach (ReportElement e in Elements)
            {
                if (e is PageDetail)
                    ls.Add((PageDetail)e);
            }
            return ls;
        }
        public List<PageFooter> GetPageFooters()
        {
            List<PageFooter> ls = new List<PageFooter>();
            foreach (ReportElement e in Elements)
            {
                if (e is PageFooter)
                    ls.Add((PageFooter)e);
            }
            return ls;
        }
        public List<ReportFooter> GetReportFooters()
        {
            List<ReportFooter> ls = new List<ReportFooter>();
            foreach (ReportElement e in Elements)
            {
                if (e is ReportFooter)
                    ls.Add((ReportFooter)e);
            }
            return ls;
        }
        public List<ReportCols> GetReportCols()
        {
            List<ReportCols> ls = new List<ReportCols>();
            foreach (ReportElement e in Elements)
            {
                if (e is ReportCols)
                    ls.Add((ReportCols)e);
            }
            return ls;
        }

        private object GetCurrentValue(int RowIndex, DataRow dataRow, string ContentValue)
        {
            string contentOut = "";
            if (dataRow.Table.Columns.Contains(ContentValue))
            {
                if (!dataRow.IsNull(ContentValue))
                {
                    return dataRow[ContentValue];
                }
            }
            else if (ContentValue == Tags.PAGEINDEX)
            {
                return exporter.PageCount + 1;
            }
            else if (ContentValue == Tags.ROWINDEX)
            {
                return RowIndex + 1;
            }
            else if (Exporter.Parameters.ContainsKey(ContentValue))
            {
                return Exporter.Parameters[ContentValue];
            }
            else
            {
                decimal value = 0;
                if (CalculateField(ContentValue, dataRow, out value))
                {
                    return value;
                }
            }

            return null;
        }
        public string DataBindValue(int RowIndex, DataRow dataRow, string Content)
        {
            string contentOut = "";
            int index = Content.IndexOf(Tags.BEGINVALUE);
            int currIndex = 0;
            while (index >= 0)
            {
                contentOut += Content.Substring(currIndex, index - currIndex);
                int indexEnd = Content.IndexOf(Tags.ENDVALUE, index + 1);
                if (indexEnd > 0)
                {
                    string ContentValue = Content.Substring(index + Tags.BEGINVALUE.Length, indexEnd - index - Tags.BEGINVALUE.Length).Trim();
                    string ContentEquation = ContentValue;
                    int indexFormat = ContentValue.IndexOf("{");
                    int indexEndFormat = ContentValue.IndexOf("}");
                    string strFormat = "";
                    if (indexFormat > 0)
                    {
                        if (indexFormat < indexEndFormat)
                        {
                            strFormat = ContentValue.Substring(indexFormat, indexEndFormat - indexFormat + 1);
                        }
                        ContentValue = ContentValue.Substring(0, indexFormat);
                    }


                    if (ContentValue.IndexOf(Tags.SUM + "(") == 0)
                    {

                        decimal total = 0;
                        int index1 = Tags.SUM.Length + 1;
                        int index2 = ContentValue.LastIndexOf(")");
                        if (index2 > index1)
                        {
                            ContentValue = ContentValue.Substring(index1, index2 - index1);
                        }
                        object val = GetCurrentValue(RowIndex, RowsAffected[0], ContentValue);
                        if ((val != null) && (eTMS.Commons.Common.IsNumber(val)) || dataRow.Table.Columns.Contains(ContentValue))
                        {
                            total = eTMS.Commons.Common.ConvertNumber(val);
                            for (int i = 1; i < RowsAffected.Length; i++)
                            {
                                val = GetCurrentValue(RowIndex, RowsAffected[i], ContentValue);
                                total += eTMS.Commons.Common.ConvertNumber(val);
                            }
                            if (strFormat.Length == 0)
                            {
                                contentOut += Convert.ToString(total);
                            }
                            else
                            {
                                try
                                {
                                    contentOut += string.Format(strFormat, total);
                                }
                                catch
                                {
                                }
                            }
                        }
                        else
                        {
                            contentOut += "&nbsp;";
                        }
                    }
                    else if (ContentValue.IndexOf(Tags.SPELL + "(") == 0)
                    {

                        decimal total = 0;
                        int index1 = Tags.SPELL.Length + 1;
                        int index2 = ContentValue.LastIndexOf(")");
                        if (index2 > index1)
                        {
                            ContentValue = ContentValue.Substring(index1, index2 - index1);
                        }
                        object val = GetCurrentValue(RowIndex, dataRow, ContentValue);
                        if ((val != null) && (eTMS.Commons.Common.IsNumber(val)))
                        {
                            contentOut += eTMS.Commons.Common.ReadNumBer(eTMS.Commons.Common.ConvertNumber(val).ToString());
                        }
                        else
                        {
                            contentOut += "&nbsp;";
                        }
                    }
                    else if (ContentValue.IndexOf(Tags.BARCODE + "(") == 0)
                    {
                        int index1 = Tags.BARCODE.Length + 1;
                        int index2 = ContentValue.LastIndexOf(")");
                        if (index2 > index1)
                        {
                            ContentValue = ContentValue.Substring(index1, index2 - index1);
                        }
                        string[] arrays = ContentValue.Split(',');
                        object val = GetCurrentValue(RowIndex, dataRow, arrays[0]);
                        int w = 180;
                        int h = 64;
                        if (arrays.Length == 3)
                        {
                            int.TryParse(arrays[1], out w);
                            int.TryParse(arrays[2], out h);
                        }
                        string fileName = HtmlReportExporter.TmpDir.TrimEnd('\\') + "\\" + DateTime.Now.ToString("yyyyMMdd") + "\\" + RowIndex.ToString() + ".png";
                        BarCodeRender.WriteBarcode(val.ToString(), w, h, fileName);
                        contentOut += "<img src='" + fileName + "'/>";
                    }
                    else
                    {
                        object value = GetCurrentValue(RowIndex, dataRow, ContentValue);
                        if (strFormat.Length == 0)
                        {
                            contentOut += value;
                        }
                        else
                        {
                            try
                            {
                                if (value != null)
                                {

                                    contentOut += string.Format(strFormat, value);
                                }
                                else
                                {
                                    contentOut += "&nbsp;";
                                }
                            }
                            catch
                            {
                            }
                        }
                    }
                }
                currIndex = indexEnd + Tags.ENDVALUE.Length;
                index = Content.IndexOf(Tags.BEGINVALUE, index + 1);
            }
            contentOut += Content.Substring(currIndex);
            return contentOut;
        }

        private bool CalculateField(string Content, DataRow row, out decimal value)
        {
            Content = Content.Replace(" ", "");
            int indexStart = 0;
            List<string> lsEquations = new List<string>();
            for (int i = 0; i < Content.Length; i++)
            {
                if ((Content[i] == '*') || (Content[i] == '/') || (Content[i] == '+') || (Content[i] == '-') || (Content[i] == '(') || (Content[i] == ')'))
                {
                    string st = Content.Substring(indexStart, i - indexStart);
                    if (st.Trim().Length > 0)
                        lsEquations.Add(Content.Substring(indexStart, i - indexStart));
                    st = Content.Substring(i, 1);
                    if (st.Trim().Length > 0)
                        lsEquations.Add(Content.Substring(i, 1));
                    indexStart = i + 1;
                }
                else if (i == Content.Length - 1)
                {
                    string st = Content.Substring(indexStart, Content.Length - indexStart);
                    if (st.Trim().Length > 0)
                        lsEquations.Add(Content.Substring(indexStart, Content.Length - indexStart));
                }
            }
            return CalculateField(0, lsEquations.Count - 1, lsEquations, out value, row);
        }
        private bool CalculateField(int indexStart, int indexEnd, List<string> lsEquation, out decimal value, DataRow dataRow)
        {
            value = 0;
            decimal currentValue = 1;
            decimal sumValue = 0;
            if (indexEnd < indexStart) return false;
            if (indexStart == indexEnd)
            {
                decimal tempValue1 = 0;
                if (!eTMS.Commons.Common.IsNumber(lsEquation[indexStart]))
                {

                    if (!dataRow.Table.Columns.Contains(lsEquation[indexStart]))
                    {
                        if (exporter.Parameters.ContainsKey(lsEquation[indexStart]))
                        {
                            if (!eTMS.Commons.Common.IsNumber(exporter.Parameters[lsEquation[indexStart]]))
                            {
                                return false;
                            }
                            tempValue1 = eTMS.Commons.Common.ConvertNumber(exporter.Parameters[lsEquation[indexStart]]);
                            value = tempValue1;
                            return true;
                        }
                        return false;
                    }
                    if ((!eTMS.Commons.Common.IsNumber(dataRow[lsEquation[indexStart]])) && !dataRow.IsNull(lsEquation[indexStart]))
                    {
                        return false;
                    }
                    tempValue1 = eTMS.Commons.Common.ConvertNumber(dataRow[lsEquation[indexStart]]);
                }
                else
                {
                    tempValue1 = eTMS.Commons.Common.ConvertNumber(lsEquation[indexStart]);
                }
                value = tempValue1;
                return true;
            }
            List<decimal> lsValues = new List<decimal>();
            List<string> lsSubEquations = new List<string>();
            for (int i = indexStart; i <= indexEnd; i++)
            {
                if (lsEquation[i].Trim().ToUpper() == Tags.SUM)
                {
                    int indexTem = FindEndEquation(i + 1, lsEquation);
                    if (indexTem < 0)
                    {
                        return false;
                    }
                    decimal d = 0;
                    foreach (DataRow r in this.RowsAffected)
                    {
                        decimal curr = 0;
                        if (!CalculateField(i + 2, indexEnd - 1, lsEquation, out curr, r)) break;
                        d += curr;
                    }

                    lsValues.Add(d);
                    i = indexTem;
                    continue;
                }
                else if (lsEquation[i].Trim().ToUpper() == Tags.COUNT)
                {
                    int indexTem = FindEndEquation(i + 1, lsEquation);
                    if (indexTem < 0)
                    {
                        return false;
                    }
                    lsValues.Add(RowsAffected.Length);
                    i = indexTem;
                    continue;
                }
                if (lsEquation[i] == "(")
                {
                    int indexTem = FindEndEquation(i, lsEquation);
                    if (indexTem < 0)
                    {
                        return false;
                    }
                    decimal temValue = 0;
                    if (!CalculateField(i + 1, indexTem - 1, lsEquation, out temValue, dataRow)) return false;
                    lsValues.Add(temValue);
                }
                if (!((lsEquation[i] == "*") || (lsEquation[i] == "/") || (lsEquation[i] == "+") || (lsEquation[i] == "-") || (lsEquation[i] == "(") || (lsEquation[i] == ")")))
                {
                    decimal tmpValue = 0;
                    if (!CalculateField(i, i, lsEquation, out tmpValue, dataRow))
                        return false;
                    lsValues.Add(tmpValue);
                }
                else
                {
                    switch (lsEquation[i])
                    {
                        case "*":
                        case "/":
                        case "+":
                        case "-":
                            lsSubEquations.Add(lsEquation[i]);
                            break;
                    }
                }
            }
            if (lsSubEquations.Count != lsValues.Count - 1)
                return false;
            sumValue = 0;
            currentValue = 0;
            for (int i = 0; i < lsSubEquations.Count; i++)
            {
                if ((lsSubEquations[i] == "*") || (lsSubEquations[i] == "/"))
                {
                    currentValue = lsValues[i];
                    if (lsSubEquations[i] == "*")
                    {
                        currentValue = lsValues[i + 1] * currentValue;
                    }
                    else
                    {
                        if (lsValues[i + 1] != 0)
                        {
                            currentValue = currentValue / lsValues[i + 1];
                        }
                        else
                        {
                            return false;
                        }
                    }
                    lsSubEquations.RemoveAt(i);
                    lsValues[i] = currentValue;
                    lsValues.RemoveAt(i + 1);
                    i--;
                }
            }
            lsSubEquations.Insert(0, "+");
            for (int i = 0; i < lsSubEquations.Count; i++)
            {
                if (lsSubEquations[i] == "+")
                {
                    sumValue += lsValues[i];
                }
                else if (lsSubEquations[i] == "-")
                {
                    sumValue -= lsValues[i];
                }

            }
            value = sumValue;
            return true;
        }
        private int FindEndEquation(int indexStart, List<string> lsEquations)
        {
            int tempIndex = -1;
            int count = 0;
            for (int i = indexStart + 1; i < lsEquations.Count; i++)
            {
                if (lsEquations[i] == "(")
                {
                    count++;
                }
                else if (count == 0)
                {
                    if (lsEquations[i] == ")")
                    {
                        tempIndex = i;
                        break;
                    }
                }
            }
            return tempIndex;
        }
        public abstract string DataBind(DataSet dataSource, DataRow ParentRow, DataRow dataRow, int RowIndex, string TemplateCode);
    }
    internal class ReportHeader : ReportElement
    {
        public override string DataBind(DataSet dataSource, DataRow ParentRow, DataRow dataRow, int RowIndex, string TemplateCode)
        {
            List<ReportCols> lsReportCols = GetReportCols();
            string st = TemplateCode;
            string stOut = "";
            int index = BeginTags.EndPos + Tags.ENDSCRIPT.Length;
            if (Elements.Count > 0)
            {
                for (int i = 0; i < Elements.Count; i++)
                {
                    if (index >= st.Length) break;
                    if ((Elements[i] is Report)||(Elements[i] is GroupData))
                    {
                        stOut += st.Substring(index, Elements[i].BeginTags.StartPos - index) + Elements[i].DataBind(dataSource, dataRow, null, RowIndex, TemplateCode);
                        index = Elements[i].EndTags.EndPos + Tags.ENDSCRIPT.Length;
                    }
                    else
                    {
                        stOut += st.Substring(index, Elements[i].BeginTags.StartPos - index) + Elements[i].DataBind(dataSource, ParentRow, dataRow, RowIndex, TemplateCode);
                        index = Elements[i].EndTags.EndPos + Tags.ENDSCRIPT.Length;
                    }

                }
            }
            else
            {
                stOut = st.Substring(BeginTags.EndPos + Tags.ENDSCRIPT.Length, EndTags.StartPos - BeginTags.EndPos - Tags.ENDSCRIPT.Length);
            }
            return DataBindValue(RowIndex, dataRow, stOut);
        }
    }
    internal class PageHeader : ReportElement
    {
        public override string DataBind(DataSet dataSource, DataRow ParentRow, DataRow dataRow, int RowIndex, string TemplateCode)
        {
            List<ReportCols> lsReportCols = GetReportCols();
            string st = TemplateCode;
            string stOut = "";
            int index = BeginTags.EndPos + Tags.ENDSCRIPT.Length;
            if (lsReportCols.Count > 0)
            {
                for (int i = 0; i < lsReportCols.Count; i++)
                {
                    if (index >= st.Length) break;
                    stOut += st.Substring(index, lsReportCols[i].BeginTags.StartPos - index) + lsReportCols[i].DataBind(dataSource, ParentRow, dataRow, RowIndex, TemplateCode);
                    index = lsReportCols[i].EndTags.EndPos + Tags.ENDSCRIPT.Length;
                }
            }
            else
            {
                stOut = st.Substring(BeginTags.EndPos + Tags.ENDSCRIPT.Length, EndTags.StartPos - BeginTags.EndPos - Tags.ENDSCRIPT.Length);
            }
            return DataBindValue(RowIndex, dataRow, stOut);
        }
    }
    internal class PageFooter : ReportElement
    {
        public override string DataBind(DataSet dataSource, DataRow ParentRow, DataRow dataRow, int RowIndex, string TemplateCode)
        {
            List<ReportCols> lsReportCols = GetReportCols();
            string st = TemplateCode;
            string stOut = "";
            int index = BeginTags.EndPos + Tags.ENDSCRIPT.Length;
            if (Elements.Count > 0)
            {
                for (int i = 0; i < Elements.Count; i++)
                {
                    if (index >= st.Length) break;
                    if (Elements[i] is Report)
                    {
                        stOut += st.Substring(index, Elements[i].BeginTags.StartPos - index) + Elements[i].DataBind(dataSource, dataRow, null, RowIndex, TemplateCode);
                        index = Elements[i].EndTags.EndPos + Tags.ENDSCRIPT.Length;
                    }
                    else
                    {
                        stOut += st.Substring(index, Elements[i].BeginTags.StartPos - index) + Elements[i].DataBind(dataSource, ParentRow, dataRow, RowIndex, TemplateCode);
                        index = Elements[i].EndTags.EndPos + Tags.ENDSCRIPT.Length;
                    }

                }
            }
            else
            {
                stOut = st.Substring(BeginTags.EndPos + Tags.ENDSCRIPT.Length, EndTags.StartPos - BeginTags.EndPos - Tags.ENDSCRIPT.Length);
            }
            return DataBindValue(RowIndex, dataRow, stOut);
        }
    }
    internal class PageDetail : ReportElement
    {
        public override string DataBind(DataSet dataSource, DataRow ParentRow, DataRow dataRow, int RowIndex, string TemplateCode)
        {
            string st = TemplateCode;
            string stOut = "";
            int index = BeginTags.EndPos + Tags.ENDSCRIPT.Length;
            if (Elements.Count > 0)
            {
                for (int i = 0; i < Elements.Count; i++)
                {
                    if (index >= st.Length) break;
                    if (Elements[i] is Report)
                    {
                        stOut += st.Substring(index, Elements[i].BeginTags.StartPos - index) + Elements[i].DataBind(dataSource, dataRow, null, RowIndex, TemplateCode);
                        index = Elements[i].EndTags.EndPos + Tags.ENDSCRIPT.Length;
                    }
                    else
                    {
                        stOut += st.Substring(index, Elements[i].BeginTags.StartPos - index) + Elements[i].DataBind(dataSource, ParentRow, dataRow, RowIndex, TemplateCode);
                        index = Elements[i].EndTags.EndPos + Tags.ENDSCRIPT.Length;
                    }

                }
            }
            else
            {
                stOut = st.Substring(BeginTags.EndPos + Tags.ENDSCRIPT.Length, EndTags.StartPos - BeginTags.EndPos - Tags.ENDSCRIPT.Length);
            }
            return DataBindValue(RowIndex, dataRow, stOut);
        }
    }
    internal class ReportFooter : ReportElement
    {
        public override string DataBind(DataSet dataSource, DataRow ParentRow, DataRow dataRow, int RowIndex, string TemplateCode)
        {
            List<ReportCols> lsReportCols = GetReportCols();
            string st = TemplateCode;
            string stOut = "";
            int index = BeginTags.EndPos + Tags.ENDSCRIPT.Length;
            if (Elements.Count > 0)
            {
                for (int i = 0; i < Elements.Count; i++)
                {
                    if (index >= st.Length) break;
                    if (Elements[i] is Report)
                    {
                        stOut += st.Substring(index, Elements[i].BeginTags.StartPos - index) + Elements[i].DataBind(dataSource, dataRow, null, RowIndex, TemplateCode);
                        index = Elements[i].EndTags.EndPos + Tags.ENDSCRIPT.Length;
                    }
                    else
                    {
                        stOut += st.Substring(index, Elements[i].BeginTags.StartPos - index) + Elements[i].DataBind(dataSource, ParentRow, dataRow, RowIndex, TemplateCode);
                        index = Elements[i].EndTags.EndPos + Tags.ENDSCRIPT.Length;
                    }

                }
            }
            else
            {
                stOut = st.Substring(BeginTags.EndPos + Tags.ENDSCRIPT.Length, EndTags.StartPos - BeginTags.EndPos - Tags.ENDSCRIPT.Length);
            }
            return DataBindValue(RowIndex, dataRow, stOut);
        }
    }
    internal class GroupData : ReportElement
    {
        public override string DataBind(DataSet dataSource, DataRow ParentRow, DataRow dataRow, int RowIndex, string TemplateCode)
        {
            StringBuilder strmBuilder = new StringBuilder();
            List<ReportCols> lsReportCols = GetReportCols();
            string st = TemplateCode;
            int index = BeginTags.EndPos + Tags.ENDSCRIPT.Length;
            string stOut = st.Substring(BeginTags.EndPos + Tags.ENDSCRIPT.Length, EndTags.StartPos - BeginTags.EndPos - Tags.ENDSCRIPT.Length);
            if (dataRow.Table.Columns.Contains(BeginTags.Atributes.StringValue(Tags.GROUPBY)))
            {
                Dictionary<string, List<DataRow>> dic = new Dictionary<string, List<DataRow>>();
                foreach (DataRow row in RowsAffected)
                {
                    string key = row[BeginTags.Atributes.StringValue(Tags.GROUPBY)].ToString();
                    if (!dic.ContainsKey(key))
                        dic.Add(key, new List<DataRow>());
                    dic[key].Add(row);
                }
                List<ReportHeader> lsReportHeader = GetHeaders();
                List<PageHeader> lsPageHeader = GetPageHeaders();
                List<PageDetail> lsPageDetail = GetPageDetails();
                List<PageFooter> lsPageFooter = GetPageFooters();
                List<ReportFooter> lsReportFooter = GetReportFooters();

                foreach (string key in dic.Keys)
                {
                    DataRow[] rs = dic[key].ToArray();
                    foreach (ReportElement elm in this.Elements)
                    {
                        elm.RowsAffected = rs;
                    }
                    foreach (ReportHeader rh in lsReportHeader)
                    {
                        strmBuilder.Append(rh.DataBind(dataSource, ParentRow, rs[0], 0, TemplateCode));
                    }
                    for (int i = 0; i < rs.Length; i++)
                    {
                        foreach (PageDetail pd in lsPageDetail)
                        {
                            strmBuilder.Append(pd.DataBind(dataSource, ParentRow, rs[i], i, TemplateCode));
                        }
                    }
                    foreach (ReportFooter rh in lsReportFooter)
                    {
                        strmBuilder.Append(rh.DataBind(dataSource, ParentRow, rs[0], 0, TemplateCode));
                    }

                }
            }
            return strmBuilder.ToString();

        }
    }

    internal class Report : ReportElement
    {
        public override string DataBind(DataSet dataSource, DataRow ParentRow, DataRow dataRow, int RowIndex, string TemplateCode)
        {
            string DataMember = BeginTags.Atributes.StringValue(Tags.DATAMEMBER);
            if (dataSource.Tables.Count == 0) return "";
            if (DataMember != "")
            {
                if (!dataSource.Tables.Contains(DataMember)) return "";
            }
            else
            {
                DataMember = dataSource.Tables[0].TableName;
            }
            StringBuilder strmBuilder = new StringBuilder();

            //BuildReport
            DataRow[] Rows = null;
            if (ParentRow != null)
            {
                string DataParentCol = BeginTags.Atributes.StringValue(Tags.DATAPARENTCOL);
                if (ParentRow.Table.Columns.Contains(DataParentCol))
                {
                    string DataLinkCol = BeginTags.Atributes.StringValue(Tags.DATALINKCOL);
                    if (dataSource.Tables[DataMember].Columns.Contains(DataLinkCol))
                    {
                        if (dataSource.Tables[DataMember].Columns[DataLinkCol].DataType.Equals(typeof(System.String)))
                        {
                            Rows = dataSource.Tables[DataMember].Select(DataLinkCol + "='" + ParentRow[DataParentCol].ToString() + "'");
                        }
                        else if (dataSource.Tables[DataMember].Columns[DataLinkCol].DataType.Equals(typeof(System.DateTime)))
                        {
                            Rows = dataSource.Tables[DataMember].Select(DataLinkCol + "='" + ParentRow[DataParentCol].ToString() + "'");
                        }
                        else
                        {
                            Rows = dataSource.Tables[DataMember].Select(DataLinkCol + "=" + ParentRow[DataParentCol].ToString());
                        }

                    }
                }
            }
            if (Rows == null)
                Rows = dataSource.Tables[DataMember].Select();
            if (Rows.Length > 0)
            {
                this.RowsAffected = Rows;
                foreach (ReportElement elm in Elements)
                {
                    elm.RowsAffected = Rows;
                }
                List<ReportHeader> lsReportHeader = GetHeaders();
                List<PageHeader> lsPageHeader = GetPageHeaders();
                List<GroupData> lsPageGroup = GetGroups();
                List<PageDetail> lsPageDetail = GetPageDetails();
                List<PageFooter> lsPageFooter = GetPageFooters();
                List<ReportFooter> lsReportFooter = GetReportFooters();
                int MAXROW = BeginTags.Atributes.IntValue(Tags.MAXROW);
                string BreakPageString = BeginTags.Atributes.StringValue(Tags.BREAKPAGESTRING);
                int count = 0;
                foreach (ReportHeader rh in lsReportHeader)
                {
                    strmBuilder.Append(rh.DataBind(dataSource, ParentRow, Rows[0], 0, TemplateCode));
                }
                if (AllowPageBreak && MAXROW > 0)
                {
                    strmBuilder.AppendLine("<STYLE>");
                    strmBuilder.AppendLine(@"<!--
                                                @media print .div_printer_hide{  
                                                   display:;
                                                } 
                                                @media screen {
                                                   .div_printer_hide {display:none;}
                                                   .div_printer_show {display:;}
                                                }
                                             -->");
                    strmBuilder.AppendLine("</STYLE>");
                }
                bool hasFooter = false;
                bool hasDivHide = true;
                if (AllowPageBreak && MAXROW > 0)
                {
                    strmBuilder.AppendLine("<p class=\"PAGESTYLE\">");
                }
                foreach (GroupData groupData in lsPageGroup)
                {
                    strmBuilder.Append(groupData.DataBind(dataSource, ParentRow, Rows[0],0, TemplateCode));
                }
                for (int i = 0; i < Rows.Length; i++)
                {
                    hasDivHide = true;
                    if (count == 0)
                    {
                        hasFooter = false;
                        foreach (PageHeader ph in lsPageHeader)
                        {
                            strmBuilder.Append(ph.DataBind(dataSource, ParentRow, Rows[i], i, TemplateCode));
                        }
                    }
                    count++;
                   
                    foreach (PageDetail pd in lsPageDetail)
                    {
                        strmBuilder.Append(pd.DataBind(dataSource, ParentRow, Rows[i], i, TemplateCode));
                    }
                    if (count == MAXROW)
                    {
                        if (i < Rows.Length - 1)
                        {
                            hasFooter = true;
                            count = 0;
                            foreach (PageFooter pf in lsPageFooter)
                            {
                                strmBuilder.Append(pf.DataBind(dataSource, ParentRow, Rows[i], i, TemplateCode));
                            }
                            if (AllowPageBreak && MAXROW > 0)
                            {
                                hasDivHide = false;
                                strmBuilder.AppendLine("</p>" + Tags.BEGINSCRIPT + Tags.ENDPAGE_BOOKMARK + Tags.ENDSCRIPT + "<p class=\"PAGESTYLE\" style='page-break-before:always'>");
                                Exporter.PageCount++;
                            }
                        }
                    }
                }
                bool foundFooter = false;
                for (int i = 0; i < Elements.Count; i++)
                {
                    if ((Elements[i] is PageFooter) || (Elements[i] is ReportFooter))
                    {
                        strmBuilder.Append(Elements[i].DataBind(dataSource, ParentRow, Rows[Rows.Length - 1], Rows.Length - 1, TemplateCode));
                        if ((Elements[i] is PageFooter))
                        {
                            foundFooter = true;
                            if (AllowPageBreak && hasFooter && MAXROW > 0)
                            {
                                strmBuilder.AppendLine("</p>");
                            }
                        }
                    }
                }
                if (AllowPageBreak && !foundFooter && hasFooter && MAXROW > 0)
                {
                    strmBuilder.AppendLine("</p>");
                }
            }
            //EndBuildReport
            return strmBuilder.ToString();

        }
    }
    internal class ReportCols : ReportElement
    {
        public override string DataBind(DataSet dataSource, DataRow ParentRow, DataRow dataRow, int RowIndex, string TemplateCode)
        {
            return "";
            //throw new Exception("The method or operation is not implemented.");
        }
    }
    internal class Tags
    {
        public const string BEGINREPORT = "BEGINREPORTCONTENT";
        public const string ENDREPORT = "ENDREPORTCONTENT";
        public const string BEGINREPORTHEADER = "BEGINREPORTHEADER";
        public const string ENDREPORTHEADER = "ENDREPORTHEADER";
        public const string BEGINREPORTFOOTER = "BEGINREPORTFOOTER";
        public const string ENDREPORTFOOTER = "ENDREPORTFOOTER";
        public const string BEGINPAGEHEADER = "BEGINPAGEHEADER";
        public const string ENDPAGEHEADER = "ENDPAGEHEADER";
        public const string BEGINGROUPDATA = "BEGINGROUPDATA";
        public const string ENDGROUPDATA = "ENDGROUPDATA";
        public const string BEGINPAGEFOOTER = "BEGINPAGEFOOTER";
        public const string ENDPAGEFOOTER = "ENDPAGEFOOTER";
        public const string BEGINPAGEDETAIL = "BEGINPAGEDETAIL";
        public const string ENDPAGEDETAIL = "ENDPAGEDETAIL";
        public const string BEGINCOLS = "BEGINCOLS";
        public const string ENDCOLS = "ENDCOLS";
        public const string BEGINSCRIPT = "<!--";
        public const string ENDSCRIPT = "-->";


        public const string BEGINVALUE = "#=";
        public const string ENDVALUE = "#";
        public const string DATAMEMBER = "DATAMEMBER";
        public const string DATAPARENTCOL = "DATAPARENTCOL";
        public const string DATALINKCOL = "DATALINKCOL";
        public const string GROUPBY = "GROUPBY";
        public const string MAXROW = "MAXROW";
        public const string ROWINDEX = "ROWINDEX";
        public const string COLUMNVAL = "COLUMNVAL";
        public const string COLUMNNAME = "COLUMNNAME";
        public const string BREAKPAGESTRING = "BREAKPAGESTRING";
        public const string ENDPAGE_BOOKMARK = "ENDPAGE";
        public const string PAGEINDEX = "PAGEINDEX";
        public const string SUM = "SUM";
        public const string COUNT = "COUNT";
        public const string SPELL = "SPELL";
        public const string BARCODE = "BARCODE";
        public const string PAGE_STYLE = "PAGESTYLE";
    }
    internal class ElementAtributes
    {
        System.Collections.Specialized.StringDictionary dic = new System.Collections.Specialized.StringDictionary();
        public void Add(string Name, string Value)
        {
            dic.Add(Name, Value);
        }
        public System.Collections.ArrayList Keys
        {
            get
            {
                return new System.Collections.ArrayList(dic.Keys);
            }
        }
        public System.Collections.ArrayList Values
        {
            get
            {
                return new System.Collections.ArrayList(dic.Values);
            }
        }
        public string StringValue(string Name)
        {

            if (!dic.ContainsKey(Name)) return "";
            return dic[Name];

        }
        public int IntValue(string Name)
        {

            if (!dic.ContainsKey(Name)) return 0;
            try
            {
                return int.Parse(dic[Name]);
            }
            catch
            {
            }
            return 0;

        }
        public double DoubleValue(string Name)
        {

            if (!dic.ContainsKey(Name)) return 0;
            try
            {
                return double.Parse(dic[Name]);
            }
            catch
            {
            }
            return 0;

        }
        public int Count
        {
            get
            {
                return dic.Count;
            }
        }
    }
    internal class PosTag
    {
        public int StartPos = -1;
        public int EndPos = -1;
        public string TagName = "";
        public ElementAtributes Atributes = new ElementAtributes();
    }
}